package obj

import (
	"fmt"
	"strings"
	"sync"
)

// Value represents a Scheme value
type Value interface {
	String() string
	Type() string
}

// StringValue represents a string value
type StringValue struct {
	Value string
}

func (s *StringValue) String() string {
	return fmt.Sprintf("\"%s\"", s.Value)
}

func (s *StringValue) Type() string {
	return "string"
}

// 符号表，用于存储所有创建的符号
type symbolTable struct {
	mutex   sync.RWMutex
	symbols map[string]*SymbolValue
}

var globalSymbolTable = &symbolTable{
	symbols: make(map[string]*SymbolValue),
}

// SymbolValue represents a symbol value
type SymbolValue struct {
	Name string
}

// NewSymbolValue 创建或获取一个符号对象
func NewSymbolValue(name string) *SymbolValue {
	globalSymbolTable.mutex.RLock()
	symbol, exists := globalSymbolTable.symbols[name]
	globalSymbolTable.mutex.RUnlock()
	
	if exists {
		return symbol
	}
	
	// 如果符号不存在，创建一个新的
	globalSymbolTable.mutex.Lock()
	// 双重检查，防止在获取锁期间符号被其他goroutine创建
	symbol, exists = globalSymbolTable.symbols[name]
	if !exists {
		symbol = &SymbolValue{Name: name}
		globalSymbolTable.symbols[name] = symbol
	}
	globalSymbolTable.mutex.Unlock()
	
	return symbol
}

func (s *SymbolValue) String() string {
	return s.Name
}

func (s *SymbolValue) Type() string {
	return "symbol"
}

// NilValue represents the Scheme nil value
type NilValue struct{}

func (n *NilValue) String() string {
	return "()"
}

func (n *NilValue) Type() string {
	return "nil"
}

// BooleanValue represents a boolean value
type BooleanValue struct {
	Value bool
}

func (b *BooleanValue) String() string {
	if b.Value {
		return "#t"
	} else {
		return "#f"
	}
}

func (b *BooleanValue) Type() string {
	return "boolean"
}

// FunctionValue represents a function value
type FunctionValue struct {
	Parameters []string
	Body       []interface{}
	Env        *Environment
	// Add a flag to help identify if this function is stored in the environment
	// to help break circular references
	InEnvironment bool
}

func (f *FunctionValue) String() string {
	return "#<procedure>"
}

func (f *FunctionValue) Type() string {
	return "procedure"
}

// BuiltinFunction represents a builtin function
type BuiltinFunction func(args []Value) (Value, error)

// EvaluatorAwareBuiltinFunction represents a builtin function that requires access to the evaluator
type EvaluatorAwareBuiltinFunction func(evaluator interface{}, args []Value) (Value, error)

// BuiltinValue represents a builtin procedure value
type BuiltinValue struct {
	Name string
	Fn   BuiltinFunction
	EvaluatorAwareFn EvaluatorAwareBuiltinFunction
	RequiresEvaluator bool
}

func (b *BuiltinValue) String() string {
	return fmt.Sprintf("#<builtin %s>", b.Name)
}

func (b *BuiltinValue) Type() string {
	return "builtin"
}

// PairValue represents a cons pair
type PairValue struct {
	Car Value
	Cdr Value
}

func (p *PairValue) String() string {
	return fmt.Sprintf("(%s . %s)", p.Car.String(), p.Cdr.String())
}

func (p *PairValue) Type() string {
	return "pair"
}

// IntegerValue represents an integer value

type IntegerValue struct {
	Value int64
}

func (i *IntegerValue) String() string {
	return fmt.Sprintf("%d", i.Value)
}

func (i *IntegerValue) Type() string {
	return "integer"
}

// RationalValue represents a rational value
// According to R4RS, rational numbers are exact numbers that can be expressed as a ratio of integers

type RationalValue struct {
	Numerator   int64
	Denominator int64
}

func (r *RationalValue) String() string {
	// If denominator is 1, just return the numerator
	if r.Denominator == 1 {
		return fmt.Sprintf("%d", r.Numerator)
	}
	// Otherwise, return as fraction
	return fmt.Sprintf("%d/%d", r.Numerator, r.Denominator)
}

func (r *RationalValue) Type() string {
	return "rational"
}

// RealValue represents a real number value

type RealValue struct {
	Value float64
}

func (r *RealValue) String() string {
	// Use a format that shows appropriate decimal places
	return fmt.Sprintf("%g", r.Value)
}

func (r *RealValue) Type() string {
	return "real"
}

// Environment represents a lexical environment
type Environment struct {
	store  map[string]Value
	parent *Environment
}

// NewEnvironment creates a new environment
func NewEnvironment() *Environment {
	return &Environment{
		store:  make(map[string]Value),
		parent: nil,
	}
}

// NewEnclosedEnvironment creates a new environment enclosed in another
func NewEnclosedEnvironment(parent *Environment) *Environment {
	env := NewEnvironment()
	env.parent = parent
	return env
}

// Get gets a value from the environment
func (e *Environment) Get(name string) (Value, bool) {
	value, ok := e.store[name]
	if !ok && e.parent != nil {
		return e.parent.Get(name)
	}
	return value, ok
}

// Set sets a value in the environment
func (e *Environment) Set(name string, value Value) {
	e.store[name] = value
}

// Clear removes all bindings from this environment (helps with garbage collection)
func (e *Environment) Clear() {
	// Clear all references to help garbage collection
	for k := range e.store {
		delete(e.store, k)
	}
	e.parent = nil
}

// Size returns the number of bindings in this environment
func (e *Environment) Size() int {
	return len(e.store)
}

// String returns a string representation of the environment
func (e *Environment) String() string {
	var out strings.Builder
	out.WriteString("Environment{\n")
	for name, value := range e.store {
		out.WriteString(fmt.Sprintf("  %s: %s\n", name, value.String()))
	}
	out.WriteString("}")
	return out.String()
}
